/**************************
* @file: web_client.js
* @brief: WebSocket版本Web客户端远程调用功能实现，基于RPC封装
* @date: 2025-10-15
*
**************************/

/**
* Web客户端RPC接口封装类
* 用于提供远程Web客户端操作的JavaScript接口
*/
class WebClientRpc {
    /**
    * 构造函数
    * @param {LuaRpc} luaRpc - Lua RPC实例
    */
    constructor(luaRpc) {
        this.luaRpc = luaRpc;
        this._initialized = false;
        // 创建初始化Promise但不等待其完成
        // 使用Promise的catch来避免未处理的Promise拒绝
        this._initializationPromise = this._initialize().catch(error => {
            console.error('WebClientRpc initialization failed:', error);
        });
    }

    /**
    * 异步初始化方法
    * 用于在类初始化时加载lib_web_client模块
    * @private
    */
    async _initialize() {
        try {
            // 再注册lib_web_client库
            console.log('WebClientRpc: Registering lib_web_client module...');
            await this.luaRpc.runCode(`
                if not buf then
                    buf = require("lib_buf")
                    print('lib_buf module registered')
                else
                    print('lib_buf module already registered')
                end
                if not web_client then
                    web_client = require("lib_web_client")
                    print('lib_web_client module registered')
                else
                    print('lib_web_client module already registered')
                end
            `);
            
            console.log('WebClientRpc: Required module (lib_web_client) has been registered');
            this._initialized = true;
        } catch (error) {
            console.error('Failed to initialize WebClientRpc and load required modules:', error);
            this._initialized = false;
            throw error;
        }
    }

    /**
    * 确保WebClientRpc已初始化
    * 用于在调用Web客户端方法前检查初始化状态
    * @private
    */
    async _ensureInitialized() {
        if (!this._initialized) {
            // 如果尚未初始化完成，则等待初始化
            if (!this._initializationPromise) {
                this._initializationPromise = this._initialize();
            }
            await this._initializationPromise;
        }
    }

    /**
    * 创建Web客户端连接
    * @param {string} hostname - 主机名
    * @param {number} port - 端口号
    * @param {string} caPath - CA证书路径（可选）
    * @returns {Promise<WebClient>} - 返回Web客户端对象
    */
    async create(hostname, port, caPath = null) {
        console.log(`WebClientRpc.create() 被调用，主机名: ${hostname}，端口: ${port}`);
        try {
            // 确保WebClientRpc已初始化
            await this._ensureInitialized();
            
            // 生成一个唯一的标识符用于在Lua中引用这个Web客户端对象
            const clientId = 'webClient_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
            
            // 执行web_client.create函数
            let luaCode;
            if (caPath) {
                luaCode = `${clientId} = web_client.create("${caPath}", "${hostname}", ${port})`;
            } else {
                luaCode = `${clientId} = web_client.create(nil, "${hostname}", ${port})`;
            }
            console.log(`执行Lua代码: ${luaCode}`);
            await this.luaRpc.runCode(luaCode);
            
            // 获取Web客户端对象
            const result = await this.luaRpc.getGlobal(clientId);
            
            if (result && result.value !== undefined && result.value !== null) {
                console.log(`Web客户端创建成功，主机名: ${hostname}，端口: ${port}`);
                // 创建Web客户端对象并返回
                const webClient = new WebClient(this.luaRpc, clientId);
                return webClient;
            } else {
                // Web客户端创建失败
                // 尝试获取错误信息
                const errorResult = await this.luaRpc.getGlobal('err');
                const errorMsg = errorResult && errorResult.value !== undefined ? errorResult.value : 'Unknown error';
                throw new Error(`Web客户端创建失败: ${errorMsg}`);
            }
        } catch (error) {
            console.error(`创建Web客户端失败: ${hostname}:${port}`, error);
            throw error;
        }
    }
}

/**
* Web客户端类
* 表示一个Web客户端连接实例
*/
class WebClient {
    /**
    * 构造函数
    * @param {LuaRpc} luaRpc - Lua RPC实例
    * @param {string} clientId - Lua中Web客户端对象的标识符
    */
    constructor(luaRpc, clientId) {
        this.luaRpc = luaRpc;
        this.clientId = clientId;
        this.isOpen = true;
    }

    /**
    * 从Web客户端读取数据
    * @param {number} bufferLen - 缓冲区长度（可选，默认为8192字节）
    * @returns {Promise<object>} - 返回包含数据和读取字节数的对象
    */
    async read(bufferLen = 8192) {
        console.log(`WebClient.read() 被调用，缓冲区长度: ${bufferLen}`);
        try {
            if (!this.isOpen) {
                throw new Error('Web client is closed');
            }
            
            // 执行Web客户端对象的read方法，根据lib_web_client.c的实现，它直接返回字符串和字节数
            const luaCode = `
                -- 根据lib_web_client.c的实现，直接调用read方法获取数据
                raw_data, bytes_read = ${this.clientId}:read(${bufferLen})
                data = nil
                
                if raw_data and bytes_read > 0 then
                    -- 创建buffer并写入原始数据
                    buffer = buf.create(bytes_read + 1)
                    
                    -- 使用lib_buf的write_str方法直接写入字符串数据
                    buffer:write_str(raw_data)
                    
                    -- 重置buffer的位置到开始
                    buffer:sleek(0)
                    
                    -- 使用lib_buf的read_base64方法将数据转换为base64字符串
                    base64_data = buffer:read_base64(bytes_read)
                    buffer:destroy()
                    data = base64_data
                end
            `;
            
            console.log(`执行Lua代码读取数据并转换为base64`);
            await this.luaRpc.runCode(luaCode);
            
            // 获取数据和读取的字节数
            const dataResult = await this.luaRpc.getGlobal('data');
            const bytesReadResult = await this.luaRpc.getGlobal('bytes_read');
            
            // 确保bytes_read是有效的数字
            const bytesRead = bytesReadResult && bytesReadResult.value !== undefined ? bytesReadResult.value : 0;
            
            if (bytesRead > 0 && dataResult && dataResult.value !== undefined) {
                return {
                    data: dataResult.value,  // 返回base64编码后的数据
                    bytesRead: bytesRead
                };
            } else if (bytesRead === 0) {
                // 读取到0字节，但没有错误，返回空数据
                return {
                    data: '',
                    bytesRead: 0
                };
            } else {
                // 读取失败，尝试获取错误信息
                const errorResult = await this.luaRpc.getGlobal('err');
                // 增强错误消息，确保即使err为null/undefined也能提供有意义的错误信息
                let errorMsg = 'Unknown error';
                if (errorResult && errorResult.value !== undefined && errorResult.value !== null) {
                    errorMsg = errorResult.value;
                } else {
                    // 提供更多上下文信息，包括响应状态
                    errorMsg = `无法读取数据，bytesRead: ${bytesRead}, dataResult: ${dataResult ? JSON.stringify(dataResult) : 'undefined'}`;
                }
                throw new Error(`读取数据失败: ${errorMsg}`);
            }
        } catch (error) {
            console.error('从Web客户端读取数据失败', error);
            throw error;
        }
    }

    /**
    * 向Web客户端写入数据
    * @param {string|ArrayBuffer} data - 要写入的数据
    * @returns {Promise<number>} - 返回写入的字节数
    */
    async write(data) {
        console.log('WebClient.write() 被调用');
        try {
            if (!this.isOpen) {
                throw new Error('Web client is closed');
            }
            
            // 生成一个唯一的标识符用于在Lua中引用这个数据
            const dataId = 'webClientData_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
            
            // 执行Web客户端对象的write方法
            let luaCode;
            if (data instanceof ArrayBuffer || ArrayBuffer.isView(data)) {
                // 对于ArrayBuffer或ArrayBufferView（如Uint8Array），将其转换为base64并在Lua中解码
                let uint8Array;
                if (data instanceof ArrayBuffer) {
                    uint8Array = new Uint8Array(data);
                } else {
                    // 对于ArrayBufferView（如Uint8Array），直接使用
                    uint8Array = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
                }
                
                const base64Data = btoa(String.fromCharCode.apply(null, uint8Array));
                
                luaCode = `
                    -- 解码base64数据并写入
                    base64_str = "${base64Data}"
                    -- 使用 base64 编码后的长度创建足够大的 buffer
                    buffer = buf.create(#base64_str)
                    decoded_len = buffer:write_base64(base64_str)
                    buffer:sleek(0)
                    -- 从buffer读取字符串，然后传递给web_client:write()
                    str_data = buffer:read_str(decoded_len)
                    bytes_written = ${this.clientId}:write(str_data)
                    buffer:destroy()
                `;
                console.log(`执行Lua代码写入二进制数据`);
            } else if (typeof data === 'string') {
                // 对于普通字符串，直接写入
                // 注意：需要转义字符串中的引号和换行符
                const escapedData = data.replace(/"/g, '\\"').replace(/\n/g, '\\n').replace(/\r/g, '\\r');
                luaCode = `bytes_written = ${this.clientId}:write("${escapedData}")`;
                console.log(`执行Lua代码: ${luaCode}`);
            } else {
                // 对于其他类型，转换为字符串
                console.warn('WebClient.write() 接收到非字符串非二进制数据类型:', typeof data);
                const stringData = String(data);
                const escapedData = stringData.replace(/"/g, '\\"').replace(/\n/g, '\\n').replace(/\r/g, '\\r');
                luaCode = `bytes_written = ${this.clientId}:write("${escapedData}")`;
                console.log(`执行Lua代码: ${luaCode}`);
            }
            
            await this.luaRpc.runCode(luaCode);
            
            // 获取写入的字节数
            const result = await this.luaRpc.getGlobal('bytes_written');
            
            if (result && result.value !== undefined) {
                console.log(`写入字节数: ${result.value}`);
                return result.value;
            } else {
                // 写入失败，尝试获取错误信息
                const errorResult = await this.luaRpc.getGlobal('err');
                const errorMsg = errorResult && errorResult.value !== undefined ? errorResult.value : 'Unknown error';
                throw new Error(`写入数据失败: ${errorMsg}`);
            }
        } catch (error) {
            console.error('向Web客户端写入数据失败', error);
            throw error;
        }
    }

    /**
    * 关闭Web客户端连接
    * @returns {Promise<boolean>} - 返回操作是否成功
    */
    async close() {
        console.log('WebClient.close() 被调用');
        try {
            if (!this.isOpen) {
                console.log('Web client is already closed');
                return true;
            }
            
            // 执行Web客户端对象的close方法
            const luaCode = `${this.clientId}:close()`;
            console.log(`执行Lua代码: ${luaCode}`);
            await this.luaRpc.runCode(luaCode);
            
            // 清理Lua中的Web客户端对象引用
            await this.luaRpc.runCode(`${this.clientId} = nil`);
            
            this.isOpen = false;
            console.log('Web client closed successfully');
            return true;
        } catch (error) {
            console.error('关闭Web客户端失败', error);
            throw error;
        }
    }
}

/**
* 导出WebClientRpc类到全局对象
*/
// 浏览器环境中，添加到全局对象
if (typeof self !== 'undefined') {
    self.WebClientRpc = WebClientRpc;
}

// 兼容旧版浏览器的window对象
if (typeof window !== 'undefined') {
    window.WebClientRpc = WebClientRpc;
}